So whilst being able to communicate between the main and render a process using IPC is great, registering
multiple channel listeners on either end can quickly become unorganized and confusing.
That said, in the last lesson we did see a simpler alternative for accessing mine process logic from
the renderer by means of the remote module.
However, as discussed, the remote module isn't a good fit for every application, and as from electronic
version, 10 will be disabled by default, mainly due to security concerns.
So with that, Electron's IPSI modules have introduced an alternative for handling logic or references
between processes without the inclusion of the remote module.
Before I demonstrate, however, let's set up a typical, albeit simple scenario.
As before, let's say we need to invoke a dialogue from the Renderer process, but have a strict policy
of not using the remote module.
I'll start by explicitly disabling it on the main windows where the contents set enable remote module,
this time to false.
Again, as from electron version 10, this will be the default, but nonetheless this is now disabled.
Then with that done, let's create a simple function in the main process for displaying a message box
dialogue with a few options.
Dialogue being a main process module of course function.
Ask fruit in which I'll start by defining a few options or fruits as per the function name assigning
to fruits an array.
This will be our dialog buttons with apple, orange and grape create the dialogue dialogue dot show
message box will require the dialogue module and the second passing this and options object with a dialogue
message parameter.
Say pick a fruit.
And buttons.
Being this fruit array require that module from electron dialogue, then what we still need to do is
handle the user's selection.
So one of these fruits, depending on which button the user clicks, return fruits.
We don't know the index yet.
So get that index from the dialogue, assigning to choice the dialogues return value.
This is a promise, but we'll fix that in a second.
Checking the button index on that return via the response property.
So returning one of these, the one at the index of the clicked button or response right now, choice
will simply hold a promise, though, so change this function to be async, meaning this entire function
now automatically returns a promise itself and to make sure we have the value of the promise returned
by the dialogue and assign that to choice and not the promise.
Make this a wait.
If you're not familiar with async and await, I've linked to some explanations in the lesson.
Resources definitely worth knowing for anyone working with modern JavaScript.
OK, that's our dialogue function done.
I'll call it right in the main process to make sure it's working again after a few seconds.
So in create window, start with a time out.
In which we can call ask fruit.
Remember, this now returns a promise as it's an asynchronous function, so resolve the return promise
with then accessing in its callback the value of the selected fruit or onto.
Which I'll just log out in the main process after three seconds.
Save.
A few moments later, we get the dialogue, I'll pick orange, check the terminal, and there we have
the selected button value locked out, meaning everything is working.
But now let's initiate this from the renderer process to start with.
Let's see what it would look like using basic epoxy messaging.
Create the button to trigger the dialogue first.
So in index on HTML, add a new button with a preceding break to put it on its own line, giving this
button an idea of USQUE just so we can select it, pick a fruit that will do so over and render renderer
dodges.
Start by selecting this button element document element by id id being ask and listen on this button
element for a click add event listener for a click with a callback to fire when it's clicked.
So as mentioned, let's start by doing this with plain ipsi messages.
Require the ipsi render a module const ipca renderer.
Calling in the click handler ipsi renderer send so sending to the main process on the Aske Fruit Channel,
we don't actually need to send anything with this as we are simply telling the main process to display
the dialogue.
Then back in the main process, listen for any incoming messages on that channel.
Require that ipsi main module.
IPSI main.
And listen with IPSI Maine on Aske Fruit, that channel we are sending on from the renderer past this
listener call back to fire when anything is received on this channel with the very important event argument
executing in this callback, ask fruit.
So displaying the dialogue to the user, ask for food returns, a promise being asynchronous, and that
promise will in turn wait for the dialogues, promise to resolve first.
So call then which as before contains the dialogue answer at this point.
Then we have the fruit the user picked so we can finally send it back to the renderer again using IPSI
on the original message event call reply on another channel.
Make this answer fruit sending as the one and only argument the dialogue answer.
So just to keep track, the user clicks the button, causing the renderer to message the main process.
The main processor then displays the dialogue, prompting the user to make a selection, which once
the user does, cause us the main process to send that selection back over ipsi to the renderer.
But we're not done.
The Renderer now still needs to listen for this response as well.
So back again in the renderer.
Listen with IPSC renderer on answer fruit, that response channel passing a callback with the message
event and the message arguments which I log out in this renderer or dev tools.
We are only replying with one argument though, so make this a bit more logical by simply calling it
answer.
They're all done.
Save this which reloads the app, click the button, closing the window to message the main process
and show us the dialog.
Pick one of these, I'll say Apple, which is received by the main process and messaged back to the
Windows process where we again listen for it and lock it out.
So this works.
And whilst it probably doesn't seem like that big a deal, once you start getting to tens or even hundreds
of functions, channel naming and listeners can become very hard to manage something.
The remote module would have simplified a lot.
But as mentioned several times, the remote module isn't always an option.
And for that reason, we now have two IPC methods that simplify the process of handling logic.
First, in the Renderer process, we have IPSI invoke to invoke a function in the main process and then
to receive and handle such invocations.
We have IPSI handle in the main process, so let's convert everything we've just added to the app to
instead use these two methods in the renderer.
I'll get rid of the answer listener.
No need for that.
And still in the buttons.
Click Handler replace the send method with ipsi renderer invoke.
I'll use the same channel name this time basically telling the main process what needs invoking Aske
Fruit.
That's it.
Will add the handler in a second.
But first, over in the main process we can now handle the specific invocation instead of listening
on a channel persay get rid of everything in this listener, changing it to handle aske fruit matching
the invoke method, still taking a callback, although we could have just used the function directly
instead of a callback.
But Inya execute and return aske fruit.
That's it.
Ask for it returns a promise of course.
So we need to handle that back in the renderer directly on the invoke method call then containing the
answer which I'll lock out.
Click the button again.
Picking Apple, and they're exactly as before we get the response from the main process, but this time
without a complicated back and forth with various channel names.
So again, whilst this might seem like a small convenience, invoke and handle should be the go to when
communicating logic between processors and will make IPSI message dense applications infinitely more
manageable.